home *** CD-ROM | disk | FTP | other *** search
- /*
- File: DialogCode.c
-
- Contains: a sample application showing how to implement a
- modeless dialog with a couple of controls.
-
- Written by: Nitin Ganatra
-
- Copyright: Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 8/9/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
-
- #include <Dialogs.h>
- #include "SampleHeader.h"
-
- extern Boolean gDone;
- extern Boolean gInBackground;
-
- /*-------------------------------------------------------------------------------------*/
- /*
- GetCtlHandle - Just a handy way to get a control's handle given only the item
- number and the dialog.
- */
- static ControlHandle GetCtlHandle(DialogPtr theDialog, short theItem)
- {
- Handle theControl;
- short aType;
- Rect aRect;
-
- GetDialogItem(theDialog, theItem, &aType, &theControl, &aRect);
- if (theControl == nil )
- DebugStr((StringPtr)"\pGetDItem in GetCtlHandle failed");
-
- return (ControlHandle)theControl;
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- SetDialogControlHilite - makes the control active and sets the control value to
- whatever you want.
-
- */
- static void SetDialogControlHilite(DialogPtr theDialog, short whichItem, Boolean isHilited)
- {
- ControlHandle theControl;
-
- theControl = GetCtlHandle(theDialog, whichItem);
- if (theControl == nil )
- {
- DebugStr((StringPtr)"\pGetCtlHandle in SetDialogControlHilite failed");
- return;
- }
- HiliteControl(theControl, 0);
- SetControlValue(theControl, isHilited);
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DisableDialogControl - disables a dialog control by deactivating it (to turn off
- hit detection) and sets its value to 0.
- */
- static void DisableDialogControl(DialogPtr theDialog, short whichItem)
- {
- ControlHandle theControl;
-
- theControl = GetCtlHandle(theDialog, whichItem);
- if ( theControl != nil )
- {
- SetControlValue(theControl, 0);
- HiliteControl(theControl, 255);
- }
- else
- DebugStr((StringPtr)"\pthe handle was nil");
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DoDialogEvent - After checking that EventFilter's result is TRUE, this calls
- DialogSelect to check if any controls were hit, and if so this acts accordingly.
- */
- void DoDialogEvent(EventRecord *theEvent)
- {
- DialogPtr theDialog = (DialogPtr)FrontWindow();
- short theItem;
- GrafPtr origPort;
-
- GetPort(&origPort);
- SetPort(theDialog);
-
- if ( EventFilter(theEvent, theDialog) != false )
- {
- if ( DialogSelect(theEvent, &theDialog, &theItem) == true )
- {
- if ( theDialog != nil )
- {
- ControlHandle tempHandle;
- short newTEItem = kEditTextField;
- Boolean newControlVal = true;
-
- switch ( theItem )
- {
- case kEditCheckItem:
- /* if this is hit, toggle the check box. We'll also */
- /* update the edit text field no matter what, since */
- /* its state depends on the check item. */
- tempHandle = GetCtlHandle(theDialog, kEditCheckItem);
-
- if ( GetControlValue(tempHandle) == true )
- {
- newControlVal = false;
- newTEItem = -1;
- }
-
- SetDialogControlHilite(theDialog, kEditCheckItem, newControlVal);
- SelectDialogItemText(theDialog, newTEItem, 0, 0);
- InvalThisItemRect(theDialog, kEditTextField);
- break;
-
- case kEditTextField:
- break;
-
- case kCancelButton:
- case kOkayButton:
- /* in either case, just throw out the dialog and return */
- DisposeDialog(theDialog);
- break;
-
- }
- }
- }
- }
-
- SetPort(origPort);
- return;
-
- BailOut:
- DebugStr((StringPtr)"\pGetCtlHandle in DoDialogEvent failed");
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- FakeButtonHilite - The recommended way to fake a button being hit. If the user
- hits escape to quit a dialog, this is called to give visual feedback that the
- dialog is cancelled.
- */
- static void FakeButtonHilite(DialogPtr theDialog, short buttonItemNum)
- {
- unsigned long throwAway;
-
- ControlHandle buttonHandle = GetCtlHandle(theDialog, buttonItemNum);
- if ( buttonHandle != nil )
- {
- HiliteControl(buttonHandle, true);
- Delay(8, &throwAway);
- HiliteControl(buttonHandle, false);
- }
-
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- InvalThisItemRect - A handly way to invalidate a dialog item. This is used to
- invalidate the edit text field of the dialog in response to the check box being
- hit.
- */
- static void InvalThisItemRect(DialogPtr theDialog, short theEditItem)
- {
- Handle editTextItem;
- short aType;
- Rect editTextRect;
- GrafPtr oldPort;
-
- GetPort(&oldPort);
- SetPort(theDialog);
-
- GetDialogItem(theDialog, theEditItem, &aType, &editTextItem, &editTextRect);
- InsetRect(&editTextRect, -5, -5);
- InvalRect(&editTextRect);
-
- SetPort(oldPort);
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- CreateModelessDialog - Creates the modeless dialog (from a DLOG resource) and sets
- up the initial state of the controls and user items. Note that it also allocates
- two globals that will always point to the user item proc routines. This is needed
- only once and can be called by all sebsequent calls to CreateModelessDialog, because
- the routines won't change. In the 68k world, these routines are redefined to just
- be plain old proc pointers, and on PowerPC bulids they use real UPPs.
- */
- void CreateModelessDialog(void)
- {
- short tempType;
- Handle tempHandle;
- Rect tempRect;
- DialogPtr theNewDialog;
- static UserItemUPP procForDimUserItem = nil;
- static UserItemUPP procForBorderUserItem = nil;
-
- theNewDialog = GetNewDialog(kModelessDialogID, nil, (WindowPtr)-1);
-
- if ( theNewDialog != nil )
- {
- if ( procForDimUserItem == nil )
- procForDimUserItem = NewUserItemProc(DimEditLine);
-
- if ( procForBorderUserItem == nil )
- procForBorderUserItem = NewUserItemProc(DrawButtonBorder);
-
- SetDialogControlHilite(theNewDialog, kEditCheckItem, true);
-
- SelectDialogItemText(theNewDialog, kEditTextField, 0, 0);
-
- /* set up the user item that will dim the edit line when it is disabled */
- GetDialogItem(theNewDialog, kEditUserItem, &tempType, &tempHandle, &tempRect);
- SetDialogItem(theNewDialog, kEditUserItem, tempType, (Handle)procForDimUserItem, &tempRect);
-
- /* set up the user item that will draw the button border */
- GetDialogItem(theNewDialog, kOkayUserItem, &tempType, &tempHandle, &tempRect);
- SetDialogItem(theNewDialog, kOkayUserItem, tempType, (Handle)procForBorderUserItem, &tempRect);
- }
- else
- DebugStr((StringPtr)"\pGetNewDialog failed");
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DimEditLine - If the dialog is not frontmost and the edit check box is false, this
- will draw the edit text dialog item in 'disabled' mode.
- */
- static pascal void DimEditLine(WindowPtr theDialog, short theItem)
- {
- ControlHandle theControl;
-
- theControl = GetCtlHandle(theDialog, kEditCheckItem);
- /* only do it if the checkbox is false */
- if ( (GetControlValue(theControl) == false) || (theDialog != FrontWindow()) )
- {
- PenState thePen;
- short itemType;
- Handle itemHandle;
- Rect dimRect;
-
- /* Save and restore the pen state so we don't mess things up for other */
- /* drawing routines */
- GetPenState(&thePen);
- GetDialogItem(theDialog, theItem, &itemType, &itemHandle, &dimRect);
- PenMode(notPatBic);
- PenPat(&qd.gray);
- PaintRect(&dimRect);
- SetPenState(&thePen);
-
- }
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- HiliteAllControls - This is used in response to activate events for the dialog. If
- an activate event is sent, hilite all controls to be active, and if its a deactivate
- event, unhilite all controls.
- */
- static void HiliteAllControls(DialogPtr theDialog, short hiliteCode)
- {
- ControlHandle theControl;
-
- InvalThisItemRect(theDialog, kEditTextField);
-
- theControl = GetCtlHandle(theDialog, kEditCheckItem);
- if ( theControl != nil )
- HiliteControl(theControl, hiliteCode);
-
- theControl = GetCtlHandle(theDialog, kCancelButton);
- if ( theControl != nil )
- HiliteControl(theControl, hiliteCode);
-
-
- theControl = GetCtlHandle(theDialog, kOkayButton);
- if ( theControl != nil )
- HiliteControl(theControl, hiliteCode);
-
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DrawButtonBorder - Standard way to draw a border around the default button.
- */
- static pascal void DrawButtonBorder(WindowPtr theDialog, short theItem)
- {
- #pragma unused (theItem)
- Handle theControl;
- short aType;
- Rect aRect;
-
- GetDialogItem((DialogPtr)theDialog, kOkayButton, &aType, &theControl, &aRect);
-
- PenSize(3,3);
- InsetRect(&aRect, -4, -4);
- FrameRoundRect(&aRect, 16,16);
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DoCut - Zero out the scrap and cut the current selection from the current edit text
- field. Done in response to the Cut menu command (either by key or mouse).
-
- Note that we don't have to worry about putting the TEScrap->DeskScrap stuff
- in response to suspend/resume events, because the desk scrap is always
- kept up-to-date.
- */
- void DoCut(DialogPtr theDialog)
- {
- HiliteMenu(kEditMenu);
- (void)ZeroScrap();
- DialogCut(theDialog);
- if ( TEToScrap() != noErr )
- DebugStr((StringPtr)"\pProblem going from TE->desk scrap");
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DoCut - Zero out the scrap and copy the current selection from the current edit text
- field. Done in response to the Copy menu command (either by key or mouse).
-
- Note that we don't have to worry about putting the TEScrap->DeskScrap stuff
- in response to suspend/resume events, because the desk scrap is always
- kept up-to-date.
- */
- void DoCopy(DialogPtr theDialog)
- {
- HiliteMenu(kEditMenu);
- (void)ZeroScrap();
- DialogCopy(theDialog);
- if ( TEToScrap() != noErr )
- DebugStr((StringPtr)"\pProblem going from TE->desk scrap");
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DoPaste - Paste the current selection from the current edit text
- field. Done in response to the Paste menu command (either by key or mouse).
-
- Note that we don't have to worry about putting the TEScrap->DeskScrap stuff
- in response to suspend/resume events, because the desk scrap is always
- kept up-to-date.
- */
- void DoPaste(DialogPtr theDialog)
- {
- if ( TEFromScrap() != noErr )
- DebugStr((StringPtr)"\pProblem going from desk scrap->TE");
- HiliteMenu(kEditMenu);
- DialogPaste(theDialog);
-
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DoClear - Cut the current selection from the current edit text field, but don't
- add it to the scrap. Done in response to the Cut menu command (either by key
- or mouse).
- */
- void DoClear(DialogPtr theDialog)
- {
- HiliteMenu(kEditMenu);
- DialogDelete(theDialog);
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- DoDialogNullEvent - This handles updating the cursor as it flys over an active edit
- text field. It also calls DialogSelect which is necessary if you have any edit
- text dialog fields, and you want that cursor to blink.
- */
- void DoDialogNullEvent(EventRecord *theEvent)
- {
- WindowPtr currFrontWindow = FrontWindow();
- short throwAwayItem;
- GrafPtr origPort;
-
- GetPort(&origPort);
- SetPort(currFrontWindow);
-
- if ( currFrontWindow != nil )
- {
- if ( (((WindowRecord *)currFrontWindow)->windowKind == dialogKind)
- && !gInBackground )
- {
- Point tempPt;
- Rect editFieldRect;
- short throwAwayType;
- Handle throwAwayHandle;
-
- GetDialogItem(currFrontWindow, kEditTextField, &throwAwayType, &throwAwayHandle, &editFieldRect);
- GetMouse(&tempPt);
- if ( PtInRect(tempPt, &editFieldRect)
- && (GetControlValue(GetCtlHandle(currFrontWindow, kEditCheckItem)) == true) )
- {
- CursHandle theCursor;
-
- theCursor = GetCursor(iBeamCursor);
- HLock((Handle)theCursor);
- SetCursor(*theCursor);
- HUnlock((Handle)theCursor);
- }
- else
- SetCursor(&qd.arrow);
-
- DialogSelect(theEvent, &currFrontWindow, &throwAwayItem);
-
- }
- }
-
- SetPort(origPort);
-
- }
-
-
- /*-------------------------------------------------------------------------------------*/
- /*
- EventFilter - This is the first thing done if a dialog event is received, giving
- you a chance to perform any special stuff before passing control on to
- DialogSelect.
-
- If this routine returns true, the event processing will continue, and DialogSelect
- will be called to perform hit detection on the controls. If false is returned,
- it means the event is already handled and the main event loop will continue.
- */
- Boolean EventFilter(EventRecord *theEvent, WindowPtr theFrontWindow)
- {
- Handle editFieldHandle;
- short aType;
- Point tempPt;
- Rect editFieldRect;
- char theKey;
- short theHiliteCode;
-
- if ( ((WindowRecord *)theFrontWindow)->windowKind == dialogKind )
- GetDialogItem((DialogPtr)theFrontWindow, kEditTextField, &aType, &editFieldHandle, &editFieldRect);
-
- switch ( theEvent->what )
- {
- case mouseDown:
- case mouseUp:
- tempPt = theEvent->where;
- GlobalToLocal(&tempPt);
-
- /* Check if the mouseDown was in the editText field */
- /* (like for text selection or cursor placement. If */
- /* the checkbox isn't checked, do nothing and return */
- /* false so DialogSelect doesn't mess with it. */
- if ( PtInRect(tempPt, &editFieldRect) &&
- (GetControlValue(GetCtlHandle((DialogPtr)theFrontWindow, kEditCheckItem)) == false) )
- return false;
- break;
-
- case keyDown:
- case autoKey:
- theKey = theEvent->message & charCodeMask;
-
- if ( (theEvent->modifiers & cmdKey) != 0 )
- {
- long menuResult;
-
- AdjustMenus();
- menuResult = MenuKey(theKey);
-
- if ( (menuResult >> 16) != 0 )
- {
- Boolean editOpPerformed = MenuCommand(menuResult);
-
- if ( editOpPerformed == true )
- /* You may ask yourself, "Why are we exiting when an */
- /* edit operation is performed?" Well, DialogSelect */
- /* performs some automatic handling for any editText */
- /* items that may be in the Dialog, and since we've */
- /* already handled them in MenuCommand() we don't */
- /* want DialogSelect to do anything */
- return false;
- }
- }
- else if ( ((theEvent->message) & charCodeMask) == 0x1B )
- {
- /* Was Cancel hit? We could also check for Return */
- /* or Enter being hit, but in this example the edit */
- /* text field is multi-lined, so I'm quitting on */
- /* return. You get the idea.. */
- FakeButtonHilite((DialogPtr)theFrontWindow, kCancelButton);
- DisposeDialog((DialogPtr)theFrontWindow);
- return false;
- }
-
- if ( (((DialogPeek)theFrontWindow)->editField + 1 == kEditTextField)
- && (GetControlValue(GetCtlHandle((DialogPtr)theFrontWindow, kEditCheckItem)) == false) )
- /* Finally, if any non-command keystrokes were */
- /* entered and the edit field is disabled, exit. */
- return false;
-
- break;
-
- case activateEvt:
- /* This is where we take care of hiliting the */
- /* controls according to whether or not the dialog */
- /* is frontmost. */
- theFrontWindow = (WindowPtr)theEvent->message;
- if ( (theEvent->modifiers & activeFlag) == true )
- theHiliteCode = 0;
- else
- theHiliteCode = 255;
-
- HiliteAllControls((WindowPtr)theFrontWindow, theHiliteCode);
- return false;
-
- }
-
- /* If we haven't returned false by now, go ahead */
- /* and return true so DialogSelect can do its */
- /* thing, like update the window, deal with an */
- /* item hit, etc. */
- return true;
- }
-